package com.cloudweb.oa.filter;

import cn.js.fan.util.ParamUtil;
import cn.js.fan.util.StrUtil;
import cn.js.fan.web.Global;
import com.alibaba.fastjson.JSONObject;
import com.cloudweb.oa.api.ILoginUtil;
import com.cloudweb.oa.cache.SecurityCache;
import com.cloudweb.oa.cache.UserCache;
import com.cloudweb.oa.config.JwtProperties;
import com.cloudweb.oa.exception.InvalidTokenVerException;
import com.cloudweb.oa.security.AuthUtil;
import com.cloudweb.oa.service.IMobileService;
import com.cloudweb.oa.service.OnlineUserService;
import com.cloudweb.oa.utils.ConstUtil;
import com.cloudweb.oa.utils.I18nUtil;
import com.cloudweb.oa.utils.JwtUtil;
import com.cloudwebsoft.framework.util.LogUtil;
import com.redmoon.oa.Config;
import com.redmoon.oa.pvg.Privilege;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author : 
 * @date :
 * description : jwt token验证的过滤器
 */
@Slf4j
@Component
public class JwtFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private IMobileService mobileService;

    @Autowired
    private AuthUtil authUtil;

    @Autowired
    private UserCache userCache;

    @Autowired
    private I18nUtil i18nUtil;

    @Autowired
    private SecurityCache securityCache;

    @Autowired
    private ILoginUtil loginUtil;

    @Autowired
    private OnlineUserService onlineUserService;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token = jwtUtil.getToken(httpServletRequest);
        String userName = null;
        // 判断token是否有效
        if (StringUtils.hasText(token)) {
            // 获取 authentication
            UsernamePasswordAuthenticationToken authentication = null;
            try {
                authentication = jwtUtil.getAuthentication(token);
            } catch (InvalidTokenVerException e) {
                write(httpServletRequest, httpServletResponse, i18nUtil.get("kicked_out"));
                return;
            }
            if (authentication != null) {
                userName = (String) authentication.getPrincipal();
                // 如果被攻击标志为1
                if (securityCache.getUserAttackFlag(userName) == 1) {
                    write(httpServletRequest, httpServletResponse, i18nUtil.get("op_invalid"));
                    return;
                }

                com.redmoon.oa.Config cfg = com.redmoon.oa.Config.getInstance();
                boolean canMultiLogin = cfg.getBooleanProperty("canMultiLogin");
                // 判断是否多重登录
                if (!canMultiLogin) {
                    // PC防多重登录
                    if (!ParamUtil.isMobile(httpServletRequest)) {
                        String tokenInCache = loginUtil.getTokeByCache(userName);
                        if (!StrUtil.isEmpty(tokenInCache) && !token.equals(tokenInCache)) {
                            write(httpServletRequest, httpServletResponse, i18nUtil.get("auto_logout"));
                            return;
                        }
                    } else {
                        // 手机端防多重登录
                        String tokenInCache = loginUtil.getMobileTokeByCache(userName);
                        if (!StrUtil.isEmpty(tokenInCache) && !token.equals(tokenInCache)) {
                            write(httpServletRequest, httpServletResponse, i18nUtil.get("auto_logout"));
                            return;
                        }
                    }
                }

                authUtil.doLoginByUserName(httpServletRequest, userName);

                // 复制jwt，并重新设置签发时间(为当前时间)和失效时间（原来手机端会用到），也可能会有15分钟不操作，就要强制退出的要求，此时就要置新token
                // String newJwt = jwtUtil.copyJwt(token);
                // httpServletResponse.setHeader(jwtProperties.getHeader(),  newJwt);

                // String userName = (String)authentication.getPrincipal();
            }
            else {
                int re = authBySkey(httpServletRequest, httpServletResponse);
                if (re == -1 || re == -2) {
                    write(httpServletRequest, httpServletResponse, i18nUtil.get("token_expired"));
                    return;
                }
            }

            // 置当前所切换的角色
            if (Config.getInstance().isRoleSwitchable()) {
                Privilege.setCurRoleCode(httpServletRequest.getHeader(ConstUtil.CUR_ROLE_CODE));
            }
            // 置当前所切换的部门
            if (Config.getInstance().isDeptSwitchable()) {
                Privilege.setCurDeptCode(httpServletRequest.getHeader(ConstUtil.CUR_DEPT_CODE));
            }
        } else {
            // log.info("token无效：" + httpServletRequest.getRequestURI());
            int re = authBySkey(httpServletRequest, httpServletResponse);
            if (re == -1 || re == -2) {
                write(httpServletRequest, httpServletResponse, i18nUtil.get("token_expired"));
                return;
            }
        }

        // 刷新在线时间
        if (userName != null) {
            onlineUserService.refreshStayTime(httpServletRequest);
        }

        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    /**
     * 通过skey
     * @param httpServletRequest
     * @param httpServletResponse
     * @return
     */
    public int authBySkey(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        // 如果token过期
        String skey = mobileService.getSkey(httpServletRequest);
        if (StringUtils.isEmpty(skey)) {
            return 0;
        } else {
            String userName = mobileService.getUserNameBySkey(skey);
            if (userName == null) {
                LogUtil.getLog(getClass()).error("getUserNameBySkey: " + skey + " is null");
                return 0;
            }

            com.cloudweb.oa.entity.User myUser = userCache.getUser(userName);
            if (myUser == null) {
                LogUtil.getLog(getClass()).error("用户不存在: " + userName);
                return -2;
            }
            if (myUser.getIsValid() == 0) {
                LogUtil.getLog(getClass()).error("用户非法: " + userName);
                return -1;
            }

            // 登录
            authUtil.doLoginByUserName(httpServletRequest, userName);

            // 重新生成token
            String authToken = jwtUtil.generate(userName);
            httpServletResponse.setHeader(jwtProperties.getHeader(), authToken);
            // 重新生成skey
            skey = mobileService.generateSkey(userName);
            httpServletResponse.setHeader(com.cloudweb.oa.utils.ConstUtil.SKEY, skey);
            return 1;
        }
    }

    public void write(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String msg) throws IOException {
        if (httpServletRequest.getHeader("accept").contains("application/json")
                || (httpServletRequest.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(
                httpServletRequest.getHeader("X-Requested-With")))) {
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("text/html;charset=utf-8");
            PrintWriter out = httpServletResponse.getWriter();
            JSONObject json = new JSONObject();
            json.put("message", msg);
            out.append(json.toString());
        } else {
            // 手机端 accept 为 */*
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("text/html;charset=utf-8");
            PrintWriter out = httpServletResponse.getWriter();
            out.append(msg);
        }
    }
}

